#include "led_driver.h"

// 全局变量定义
static char device_buffer[BUF_SIZE] = "Hello, Misc Device!\n";  // 存储设备缓冲区数据，初始化为默认值
 // 存储映射的 GPIO 控制寄存器地址
static volatile unsigned int *vir_gpio5_dr = NULL;
static volatile unsigned int *vir_gpio1_dr = NULL;
// 文件操作函数：打开设备
static int misc_open(struct inode *inode, struct file *file)
{
    pr_info("misc_device: opened\n");  // 打开设备时输出信息
    return 0;  // 成功打开设备
}

// 文件操作函数：关闭设备
static int misc_close(struct inode *inode, struct file *file)
{
    pr_info("misc_device: closed\n");  // 关闭设备时输出信息
    return 0;  // 成功关闭设备
}

// 文件操作函数：读取设备
static ssize_t misc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    size_t len = strlen(device_buffer);  // 获取设备缓冲区数据的长度
    if (*ppos >= len)  // 如果已经读取到数据末尾，返回 0 表示没有更多数据
        return 0;

    // 限制读取的字节数为剩余数据的长度
    if (count > len - *ppos)
        count = len - *ppos;

    // 将数据从内核空间复制到用户空间
    if (copy_to_user(buf, device_buffer + *ppos, count))
        return -EFAULT;  // 如果复制失败，返回错误

    *ppos += count;  // 更新文件偏移量
    return count;  // 返回实际读取的字节数
}

// 文件操作函数：写入设备
static ssize_t misc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    if (count > BUF_SIZE - 1)  // 检查写入的数据大小是否超出缓冲区
        return -EINVAL;  // 如果超出缓冲区大小，返回无效参数错误

    // 将数据从用户空间复制到内核空间
    if (copy_from_user(device_buffer, buf, count))
        return -EFAULT;  // 如果复制失败，返回错误

    device_buffer[count] = '\0';  // 确保数据缓冲区以 null 终止
    pr_info("misc_device: received %s\n", device_buffer);  // 打印接收到的数据

    // 检查 GPIO 寄存器是否映射
    if (!vir_gpio5_dr || !vir_gpio1_dr) {
        pr_err("GPIO virtual addresses are not mapped!\n");
        return -EFAULT;  // 如果未映射，返回错误
    }

    // LED 控制逻辑：根据接收到的数据控制 LED 状态
    switch (device_buffer[1]) {
    case '0':  // 如果是控制 LED 0
        *vir_gpio5_dr = (device_buffer[0] == 'o') ?  // 如果数据为 'o'，开启 LED，否则关闭
            (*vir_gpio5_dr & ~(1 << 3)) : (*vir_gpio5_dr | (1 << 3));
        break;
    case '1':   // 如果是控制 LED 1
        *vir_gpio1_dr = (device_buffer[0] == 'o') ? 
            (*vir_gpio1_dr & ~(1 << 3)) : (*vir_gpio1_dr | (1 << 3));
        break;
    case '2':
        *vir_gpio1_dr = (device_buffer[0] == 'o') ? 
            (*vir_gpio1_dr & ~(1 << 5)) : (*vir_gpio1_dr | (1 << 5));
        break;
    case '3':
        *vir_gpio1_dr = (device_buffer[0] == 'o') ? 
            (*vir_gpio1_dr & ~(1 << 6)) : (*vir_gpio1_dr | (1 << 6));
        break;
    default:
        pr_warn("Invalid LED index: %c\n", device_buffer[1]);  // 如果 LED 索引无效，打印警告
        return -EINVAL;  // 返回无效参数错误
    }

    pr_info("LED %c set to %s\n", device_buffer[1], device_buffer[0] == 'o' ? "ON" : "OFF");  // 打印 LED 状态
    return count;  // 返回写入的数据大小
}

// 文件操作结构体定义
static const struct file_operations fops = {
    .owner = THIS_MODULE,  // 模块所有者
    .open = misc_open,  // 打开设备时调用的函数
    .release = misc_close,  // 关闭设备时调用的函数
    .read = misc_read,  // 读取设备时调用的函数
    .write = misc_write,  // 写入设备时调用的函数
};

// 定义一个杂项设备结构体
static struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,  // 动态分配次设备号
    .name = DEVICE_NAME,  // 设备名称
    .fops = &fops,  // 文件操作结构体
};

// 设备树匹配表：指定支持的设备树节点
static const struct of_device_id led_test_of_match[] = {
    { .compatible = "led0-test" },  // 支持的设备树兼容字符串
    { /* sentinel */ }  // 结束符
};
MODULE_DEVICE_TABLE(of, led_test_of_match);  // 告诉内核设备树的匹配表

// 读取设备树节点信息
int read_tree_node(u32 *reg, u32 *size)
{
    struct device_node *np;
    u32 reg_val[4];
    const char *status;
    int ret;

    np = of_find_node_by_name(NULL, "led_test");  // 查找设备树中名为 "led_test" 的节点
    if (!np) {
        pr_err("Failed to find led_test node in device tree\n");
        return -ENODEV;  // 如果找不到节点，返回错误
    }

    pr_info("Found led_test node in device tree\n");

    // 读取设备树中的 "reg" 属性值
    ret = of_property_read_u32_array(np, "reg", reg_val, 4);
    if (ret) {
        pr_err("Failed to read 'reg' property\n");
        return ret;  // 如果读取失败，返回错误
    }
    pr_info("Reg addresses and sizes:\n");
    pr_info("Address 1: 0x%x, Size 1: 0x%x\n", reg_val[0], reg_val[1]);
    pr_info("Address 2: 0x%x, Size 2: 0x%x\n", reg_val[2], reg_val[3]);
    *reg = reg_val[0];  // 解析并保存 "reg" 属性的值
    *size = reg_val[1];  // 解析并保存 "size" 属性的值

    // 映射 GPIO 寄存器地址
    vir_gpio5_dr = of_iomap(np, 0);
    vir_gpio1_dr = of_iomap(np, 1);

    if (!vir_gpio5_dr || !vir_gpio1_dr) {
        pr_err("GPIO virtual addresses are not mapped!\n");
        return -EFAULT;  // 如果映射失败，返回错误
    }

    // 读取设备树中的 "status" 属性值
    ret = of_property_read_string(np, "status", &status);
    if (ret) {
        pr_err("Failed to read 'status' property\n");
        return ret;  // 如果读取失败，返回错误
    }

    pr_info("LED test: status = %s\n", status);

    return 0;  // 成功读取设备树节点信息
}

// 驱动的 probe 函数：设备驱动加载时调用
int led_probe(struct platform_device *pdev)
{
    int ret, reg, size;

    pr_info("LED test driver probed\n");  // 驱动加载时输出信息

    ret = read_tree_node(&reg, &size);  // 读取设备树节点信息
    if (ret)
        return ret;

    // 注册杂项设备
    ret = misc_register(&misc_dev);
    if (ret)
        pr_err("Failed to register misc device\n");

    return ret;  // 返回注册结果
}

// 驱动的 remove 函数：设备驱动卸载时调用
int led_remove(struct platform_device *pdev)
{
    pr_info("LED test driver removed\n");  // 驱动卸载时输出信息
    return 0;  // 返回成功
}

// 平台驱动结构体：定义了 probe 和 remove 函数
static struct platform_driver led_driver = {
    .probe = led_probe,
    .remove = led_remove,
    .driver = {
        .name = "led-test",  // 驱动名称
        .of_match_table = led_test_of_match,  // 设备树匹配表
    },
};

// 驱动初始化函数
static int __init led_test_init(void)
{
    pr_info("Initializing LED test driver\n");  // 输出驱动初始化信息
    return platform_driver_register(&led_driver);  // 注册平台驱动
}

// 驱动退出函数
static void __exit led_test_exit(void)
{
    pr_info("Exiting LED test driver\n");  // 输出驱动退出信息
    if(!vir_gpio5_dr) iounmap(vir_gpio5_dr);  // 解除 GPIO 寄存器地址的映射
    if(!vir_gpio1_dr) iounmap(vir_gpio1_dr);  // 解除 GPIO 寄存器地址的映射
    // 注销杂项设备，确保设备已注册
    if (misc_dev.minor != MISC_DYNAMIC_MINOR) {
        pr_info("Unregistering misc device\n");
        misc_deregister(&misc_dev);
    } else {
        pr_warn("Misc device was not registered or already unregistered\n");
    }

    // 注销平台驱动，确保驱动已注册
    if (led_driver.driver.name) {
        pr_info("Unregistering platform driver\n");
        platform_driver_unregister(&led_driver);
    } else {
        pr_warn("Platform driver was not registered or already unregistered\n");
    }
}

// 模块入口和出口
module_init(led_test_init);
module_exit(led_test_exit);

// 模块元数据
MODULE_LICENSE("GPL");  // 模块许可证
MODULE_AUTHOR("Your Name");  // 作者信息
MODULE_DESCRIPTION("LED test driver to read device tree properties");  // 模块描述
MODULE_VERSION("1.0");  // 模块版本
